home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
QuickTime 1.0 for Developers
/
QuickTime 1.0 for Developers.iso
/
Programming Stuff
/
Sample Code
/
MovieConstruction
/
Movie Construction FD.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-09-05
|
12KB
|
437 lines
/************************************
*
* file: Movie Construction FD.c
*
* This program creates a movie by drawing
* frames and adding adding them one at a
* time to the movie.
*
* This program uses the sequence compression commands
* which make smaller movie files by only saving
* the changes between frames
*
*
* by Rich Williams
* January, 1991
* updated to 4.04 interfaces
*
* 8/91 added making component call to make a preview
* Updated to MPW/Think 5.0/DSG interfaces 9/91 Chris Thorman
*
***************************************************/
#include "Movies.h"
#include "QuickTimeComponents.h"
#include <Memory.h>
#include <Fonts.h>
#include <Palettes.h>
#include <OSEvents.h>
#include <Menus.h>
#include <Sound.h>
#include <ToolUtils.h>
#include <Desk.h>
#include <Resources.h>
#include <Errors.h>
#include <Packages.h>
/************************************
* Limits and Konstants
************************************/
#define kFrameX 120 /* Width & Height */
#define kFrameY 100
#define kPixelSize 32
#define kFrameCnt 25 /* Number of frames to do */
#define kTimeScale 10 /* frames per second */
/* The fixed point number for 1.00 */
#define x1Rate (Fixed) 1<<16
/************************************
* Types and globals
************************************/
/* Drawer receives these fields */
typedef struct
{
long frameX,frameY;
long frameCnt;
long pixelSize;
} animationLimits;
/************************************
* Prototypes
************************************/
static void InitToolbox(void);
static void MakeFrames(animationLimits *);
static void ConstructMovie(void);
void MakePreview(FSSpecPtr theFile, short resRefNum);
void main(void);
/************************************
*
* InitToolbox()
* Start up the tool (and the movie tools!)
*
************************************/
void InitToolbox()
{
OSErr theErr;
MaxApplZone();
InitGraf(&qd.thePort);
InitFonts();
FlushEvents(0xffff,0);
InitWindows();
InitMenus();
InitDialogs(0);
TEInit();
InitCursor();
theErr = EnterMovies(); /* Don't forget this. Real men use Alert Dialogs */
if (theErr) DebugStr((StringPtr) "\pEnterMovies Failed");
}
/************************************
*
* Construct Movie()
* Make a window and call MakeFrames
*
************************************/
void ConstructMovie()
{
WindowPtr w;
Rect r;
animationLimits al;
r.left = r.top = 0;
r.right = kFrameX;
r.bottom = kFrameY;
OffsetRect(&r,100,100);
w = NewCWindow(0,&r,(StringPtr)"\pFrames",true,0,(WindowPtr)-1,true,0);
SetPort(w);
al.frameX = kFrameX;
al.frameY = kFrameY;
al.frameCnt = kFrameCnt;
al.pixelSize = kPixelSize;
MakeFrames(&al); /* write out lots of frames */
CloseWindow(w);
}
/************************************
*
* MakeFrames(al)
* Here is where all the work happens
*
************************************/
void MakeFrames(al)
animationLimits *al;
{
short theErr; /* latest error return */
short resRefNum;
long i; /* the usual miscellaneous integer */
/* Stuff for creating the file */
Point dlgPos = {100,100}; /* Position the dialog box */
SFReply sfr; /* StdFile reply */
FSSpec mySpec; /* Data structure with filename, etc. */
short resId;
Movie gMovie; /* Our movie, track and media */
Track gTrack;
Media gMedia;
/* Stuff for drawing our frames */
GWorldPtr myGWorld,oldGWorld;
GDHandle oldGDevice;
PixMap *pm,**pmH; /* our offscreen pixmap */
char c[30]; /* a string, for NumToString */
Rect r,r2;
/* Stuff for the compressor */
char **compressedFrameBitsH; /* Buffer for the compressed data */
long maxCompressedFrameSize; /* Max size of compressed frame */
long compressedFrameSize; /* Size of current compressed frame */
CodecType codecType; /* Type of codec to use JPEG etc */
CompressorComponent codecID; /* Which variation of codecType to use */
short theDepth; /* Color depth to compress to */
CodecQ theQuality; /* Quality to compress to */
ImageDescription **imageDescriptionH; /* Contains info about the sample */
/* For frame differencing, we also have these */
ImageSequence seqID; /* Which sequence is being compressed */
unsigned char similarity; /* Measure of how similar the frame is to the previous one */
long keyFrameRate; /* # samples per key frame */
CodecQ mQuality; /* Motion quality */
/* Stuff for adding the sample */
TimeValue sampTime; /* Time sample is added to media */
/******************************
*
* Set values for Road Pizza compression
* You would let the user pick it with a dialog
*
*******************************/
codecID = anyCodec;
codecType = (CodecType) 'rpza';
theDepth = 16;
theQuality = 0x200; /* Quality is 0x100 to 0x300 */
mQuality = 0x200;
keyFrameRate = 10; /* 1 keyframe every 10 frames */
/******************************
*
* First we make an empty movie
*
*******************************/
/* Prompt the user for a file name and create it */
SFPutFile(dlgPos, (StringPtr) "\pMovie file to create:",(StringPtr)"\pTempMovie",nil,&sfr);
if (!sfr.good)
return; /* Return if cancel pressed */
ClearMoviesStickyError(); /* Clear any old errors */
theErr = FSMakeFSSpec(sfr.vRefNum, 0, (unsigned char *) sfr.fName, &mySpec);
if (theErr == fnfErr) theErr = 0;
if (theErr) DebugStr((StringPtr) "\pFSMakeFSSpec Failed");
theErr = CreateMovieFile( &mySpec, 'TVOD',0,createMovieFileDeleteCurFile,&resRefNum,&gMovie);
if (theErr) DebugStr((StringPtr) "\pCreateMovieFile Failed");
/* Create the track and media */
gTrack = NewMovieTrack(gMovie,(long)kFrameX<<16,(long)kFrameY<<16,0);
if (theErr = GetMoviesError()) DebugStr((StringPtr) "\pNewMovieTrack Failed");
gMedia = NewTrackMedia(gTrack, VideoMediaType, kTimeScale, nil,(OSType) nil);
if (theErr = GetMoviesError()) DebugStr((StringPtr) "\pNewTrackMedia Failed");
theErr = BeginMediaEdits( gMedia ); /* We do this since we are adding samples to the media */
if (theErr) DebugStr((StringPtr) "\pBeginMediaEdits Failed");
/******************************
*
* Now make a new GWorld to draw the frames to be compressed
*
*******************************/
GetGWorld(&oldGWorld,&oldGDevice); /* save the old port */
r.left = r.top = 0;
r.right = al->frameX;
r.bottom = al->frameY;
if (theErr = NewGWorld(&myGWorld,al->pixelSize,&r,nil,nil,0))
DebugStr((StringPtr) "\pNewGWorld Failed");
pmH = myGWorld->portPixMap; /* GetGWorldPixMap doesn't always work */
LockPixels(pmH);
HLock((Handle)pmH);
pm = *pmH; /* pm is pointer to pixel-map */
/******************************
*
* Now make the buffers and stuff for the compressor
*
*******************************/
imageDescriptionH = (ImageDescription **)NewHandle( 4 ); /* handle for image descriptor */
theErr = GetMaxCompressionSize(&pm,&r,theDepth,theQuality,
codecType,codecID,&maxCompressedFrameSize); /* How big a buffer do we need? */
if (theErr) DebugStr((StringPtr) "\pGetMaxCompressionSize Failed");
compressedFrameBitsH = NewHandle(maxCompressedFrameSize); /* Make the buffer */
if (!compressedFrameBitsH) DebugStr((StringPtr) "\pUnable to allocate compression buffer");
HLock(compressedFrameBitsH);
/******************************
*
* Tell the codec manager we are about to start a sequence
*
*******************************/
theErr = CompressSequenceBegin( &seqID,
&pm, nil,
&r, nil,
theDepth, codecType, codecID,
theQuality,
mQuality, keyFrameRate,
nil /* no clut */,
codecFlagUpdatePrevious,
imageDescriptionH);
if (theErr) DebugStr((StringPtr) "\pCompressSequenceBegin Failed");
/******************************
*
* Now put the movie together one frame at a time
*
*******************************/
for(i = 0; i<al->frameCnt; i++)
{
if(Button()) /* A terrific user interface */
{
FlushEvents(0xffff,0);
ExitToShell();
}
/******************************
*
* This is where we draw a single frame of the movie.
* We're only drawing black and white here, into our big
* 32-bit offscreen GWorld, because RAM is so cheap.
*
*******************************/
SetGWorld(myGWorld,nil);
EraseRect(&r); /* erase the whole area to white */
MoveTo(20,20);
NumToString(i+1,(StringPtr)&c);
DrawString((StringPtr)&c);
r2 = r;
r2.bottom = (long)r2.bottom * i / (al->frameCnt-1);
InvertRect(&r2);
/******************************
*
* Go back to the old GWorld (the Window)
* and copybit the frame into it for something to watch
*
*******************************/
SetGWorld(oldGWorld,oldGDevice);
CopyBits((BitMap *) pm,(BitMap *) *(PixMapHandle)(qd.thePort->portBits.baseAddr),&r,&r,0,0);
/******************************
*
* Compress the Frame
*
*******************************/
theErr = CompressSequenceFrame(seqID,
&pm,
&r,
codecFlagUpdatePrevious,
*compressedFrameBitsH,
&compressedFrameSize,
&similarity,
nil);
if (theErr) DebugStr((StringPtr) "\pCompressSequenceFrame Failed");
/******************************
*
* And add it to the media
*
*******************************/
theErr = AddMediaSample(gMedia,
compressedFrameBitsH,
0L,
compressedFrameSize,
(TimeValue)1,
(SampleDescriptionHandle) imageDescriptionH,
1L,
similarity?mediaSampleNotSync:0,
&sampTime);
if (theErr) DebugStr((StringPtr) "\pAddMediaSample Failed");
/* And loop back for the next frame */
}
/******************************
*
* Now close up the movie
* and throw out our buffers and stuff
*
*******************************/
theErr = CDSequenceEnd(seqID); /* Tell the codec we're done with the sequence */
if (theErr) DebugStr((StringPtr) "\pCDSequenceEnd Failed");
theErr = EndMediaEdits( gMedia ); /* We're done adding samples */
if (theErr) DebugStr((StringPtr) "\pEndMediaEdits Failed");
theErr = InsertMediaIntoTrack(gTrack,0L,0L,GetMediaDuration(gMedia),x1Rate);
if (theErr) DebugStr((StringPtr) "\pInsertMediaIntoTrack Failed");
resId = 1;
theErr = AddMovieResource( gMovie, resRefNum, &resId, (char *)sfr.fName );
if (theErr) DebugStr((StringPtr) "\pAddMovieResource Failed");
MakePreview(&mySpec,resRefNum); /* Add a preview to the file */
theErr = CloseMovieFile( resRefNum );
if (theErr) DebugStr((StringPtr) "\pCloseMovieFile Failed");
DisposeMovie(gMovie); /* We don't need the movie anymore */
DisposHandle(compressedFrameBitsH);
DisposHandle((Handle)imageDescriptionH);
DisposeGWorld(myGWorld);
}
/******************************
*
* MakePreview
* makes a preview for the movie
*
*******************************/
void MakePreview(FSSpecPtr theFile, short resRefNum)
{
ComponentInstance thePreviewMaker;
Component thePreviewComponent;
ComponentDescription tDesc;
OSErr theErr;
/* Find a preview component */
tDesc.componentType = 'prvt';
tDesc.componentSubType = 'MooV';
tDesc.componentManufacturer = 0;
tDesc.componentFlags = 0;
tDesc.componentFlagsMask = 0;
thePreviewComponent = FindNextComponent( (Component) 0,&tDesc);
/* an instance of the component */
thePreviewMaker = OpenComponent(thePreviewComponent);
if(thePreviewMaker == nil) /* Did it fail? */
return;
/* Now put the preview into the file */
theErr = PreviewerCreatePreviewForResRefNum(thePreviewMaker, resRefNum, theFile, true, nil, nil);
CloseComponent(thePreviewMaker); /* Throw out the component */
}
/******************************
*
* The main routine
* It doesn't look like much but I'm proud of it
*
*******************************/
void main()
{
InitToolbox(); /* Start up the tools */
ConstructMovie(); /* Make the movie */
}